from datetime import timedelta, datetime
from typing import Union, Any, Optional

import requests
import yagmail
from jose import jwt, JWTError
from passlib.context import CryptContext
from ronglian_sms_sdk import SmsSDK
from starlette.requests import Request

from common.config import settings

# orm 迁移生成表
# https://tortoise.github.io/migration.html
from common.exception import UnicornException

TORTOISE_ORM = {
    "connections": {"default": settings.MYSQL_DATABASE_URL},
    "apps": {
        "models": {
            "models": ["models", "aerich.models"],
            "default_connection": "default",
        },
    }
}

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")


def verify_password(plain_password: str, hashed_password: str) -> bool:
    """
    验证明文密码 vs hash密码
    :param plain_password: 明文密码
    :param hashed_password: hash密码
    :return:
    """
    return pwd_context.verify(plain_password, hashed_password)


def get_password_hash(password: str) -> str:
    """
    加密明文
    :param password: 明文密码
    :return:
    """
    return pwd_context.hash(password)


def send_message(mobile: str, captcha: str, minute: int, tid: str = '1'):
    """
    发送短信验证码
    :param mobile: 发送手机号，多个手机号使用 , 分割
    :param captcha: 验证码
    :param minute: 失效时间(分钟)
    :param tid: 模板 免费模板 默认为 '1'
    """
    sdk = SmsSDK(settings.ACCOUNT_SID, settings.ACCOUNT_TOKEN, settings.APPID)
    return sdk.sendMessage(tid, mobile, (captcha, str(minute)))


def create_access_token(subject: Union[str, Any], expires_delta: Optional[timedelta] = None):
    """
    生成token
    :param subject: 加密信息
    :param expires_delta: 有效时间
    :return:
    """
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(
            minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES
        )
    to_encode = {"exp": expire, "sub": str(subject)}
    encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
    return encoded_jwt


def payload_token(token: str):
    """解token"""
    try:
        payload = jwt.decode(
            token, settings.SECRET_KEY, algorithms=[
                settings.ALGORITHM])
        return payload.get("sub", None)
    except JWTError:
        return None


async def verif_oauth(request: Request):
    err = UnicornException('用户认证')
    if "Authorization" not in request.headers:
        raise err
    auth = request.headers.get("Authorization")
    sub = payload_token(auth)
    try:
        from dao.user import user_dao
        return await user_dao.get(id=sub)
    except Exception:
        raise err


def request_gitee(code: str):
    """用户授权成功换取 access_token"""
    token_url = f"https://gitee.com/oauth/token?grant_type=authorization_code&code={code}&" \
                f"client_id={settings.GITEE_ID}&redirect_uri={settings.GITEE_URL}&client_secret={settings.GITEE_SECRET}"
    url = "https://gitee.com/api/v5/user"
    info = requests.get(url=url, params={"access_token": requests.post(token_url).json().get("access_token")})
    return info.json()


def send_email(to: str, href: str):
    """发送邮件
    :param to: 收件人
    :param href: 激活链接
    """
    # https://blog.csdn.net/weixin_38428827/article/details/104223207
    with yagmail.SMTP(user=settings.EMAIL_USER,
                      password=settings.EMAIL_SECRET, host=settings.EMAIL_SMTP_HOST) as y:
        y.send(to, '美多商城邮箱验证', contents=f"""
        <p> 邮箱: {to}</p>
        <p><a href={href}>👇me</a></p>
        """)